//SceneManager
//Created 20/12/12
//Version 1.0
//Created By Daniel Bowler
//
//The scene manager class will hold a vector of differnt 'game' or demo
//scenes. It will be able to change scenes when a request to do so has
//been made. (probably by pressing enter)
//
//Similar to my 2D game engine, we will load our dynamic memory when
//the scene loads rather than all at the beginning. (This class
//is very similar to the GameController in my 2D engine - though
//designed from the ground up)
//
//BY DEFAULT: The initial current scene will be set to the first element in
//the scene vector. Ie, currentScene = sceneVector[0]; (see LoadScenes())
//This can be changed by removing the code and replacing it with what ever. 
//For our demo program, this will do fine. 
//
//Modified (09/01/13) : Using iterators with the scene vector rather than
//for loops. 
//
//NOTE: We MUST make sure we are safely using pointers. For every single
//scene, ensure that we are both setting all pointers to NULL in the constructor
//and ensuring that we test for null before deleting dynamic data and then
//setting it back to NULL after deleting. As it turns out, my scene loading &
//unloading method can result in a scene having its DeallocateDynamicData
//function called even if the scene has not had its AllocateDynamicData
//function called before hand. The best way to prevent horrible crashes
//when the SceneManager is released (When the game is closed), is to ENSURE
//YOU USE POINTERS SAFELY. 
//
//Note: Interestingly, we can use a dynamic_cast to take an AbstractScene pointer
//and interpret it as a subclass. I would love to demo this, but I get the feeling
//its going to be a bit useless in my inheritance hierarchy.

#pragma once

//If left uncommented, we will load the TestScene.h (last)
//#define LOAD_TEST_SCENE

//uncommented if when we open our demo application, we want
//to set the first scene (viewed) as the last scene (loaded) in our scene vector - IE, the
//one we are currently working on. 
#define OPEN_ON_LAST_SCENE

#include <vector>
#include <Windows.h>

using namespace std;

//Forward delcate AbstractScene - will #include in the .cpp file. 
//For some reason, the compiler doesnt like me #indluding AbstractScene
//in the .h file.
class AbstractScene;

class SceneManager
{
public:
	//Function that returns a pointer to the shared scene manager. 
	static SceneManager* GetInstance();
	//Releases the scene manager and all the demo scenes. 
	void Release();

	//Functions to update and render the current scene
	void UpdateCurrentSceneWithDelta(float delta);
	void RenderCurrentScene();

	//Function that returns the current scenes title in wstring format - 
	//which will work with the main window caption. 
	wstring ReturnCurrentSceneTitle();

	//Function that increments to the next scene in our vector for our demo
	//program.
	void IncrementToNextScene();

	//Function which transitions to a scene by string - flags used to 
	//determin if we will call CloseScene() on the current scene
	//and OpenScene() on new scene. 
	void TransitionToSceneWithKey(std::string sceneToMoveTo, 
		bool shouldUnloadCurrentScene, bool shouldLoadNewScene);

	//Mouse input functions - These will be called within D3DApp. The sceneManager
	//will then forward the input to the current scene
	void ForwardOnMouseDownToCurrentScene(WPARAM btnState, int x, int y, UINT originalMessage);
	void ForwardOnMouseUpToCurrentScene(WPARAM btnState, int x, int y, UINT originalMessage);
	void ForwardOnMouseMoveToCurrentScene(WPARAM btnState, int x, int y);

	//Forward the OnResize message to the current scene
	void ForwardOnResizeToCurrentScene();
																																		
private:
	//Make it a singleton
	SceneManager();
	~SceneManager();
	SceneManager(SceneManager const& copy);              //Not implemented
	SceneManager& operator = (SceneManager const& copy); //Not implemented
	static SceneManager* instance;

	//Vector of AbstractScene pointers. In truth, this could have been an array
	//but I cant be bothered to update a constant each scene I add - nor do I wish
	//to use some form of global variable to track the number of scenes. Keeping
	//things nice and simple (with c++) can never be a bad thing!
	vector <AbstractScene*> sceneVector;
	//AbstractScene pointer that will point to our current scene to render/update
	AbstractScene* currentScene;
	//Int to represent the index of the current scene in the sceneVector
	//(wont be needed with alternative loading/scene changing methods)
	unsigned currentSceneIndex;

	//Function that loads the scenes - wont call AllocateDynamicMemory just yet,
	//however. 
	void LoadScenes();

	//Im proud of this! - Load a scene via a templated function. Specify
	//the class of the scene we are trying to load in the < >
	//Eg: LoadNewSceneFromTemplate<TestScene>(L"Test Scene Title");
	template<class T> 
	void LoadNewSceneFromTemplate(wstring title);

private:
	//Loops through scenes array and finds the scene for a given key
	unsigned FindSceneIndexForKey(std::string key);
};